package com.atlin.project.controller;

import com.atlin.project.annotation.AuthCheck;
import com.atlin.project.common.BaseResponse;
import com.atlin.project.common.DeleteRequest;
import com.atlin.project.common.ErrorCode;
import com.atlin.project.common.ResultUtils;
import com.atlin.project.contant.UserConstant;
import com.atlin.project.exception.BusinessException;
import com.atlin.project.exception.ThrowUtils;
import com.atlin.project.model.domain.SysUser;
import com.atlin.project.model.domain.TaskList;
import com.atlin.project.model.dto.taskList.TaskListAddRequest;
import com.atlin.project.model.dto.taskList.TaskListQueryRequest;
import com.atlin.project.model.dto.taskList.TaskListUpdateRequest;
import com.atlin.project.model.enums.taskListEnums.TaskListStatusEnum;
import com.atlin.project.model.vo.taskList.TaskListVO;
import com.atlin.project.service.SysUserService;
import com.atlin.project.service.TaskListService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 任务清单接口
 *
 * @author atlin
 */
@RestController
@RequestMapping("/taskList")
@Slf4j
public class TaskListController {

    @Resource
    private TaskListService taskListService;

    @Resource
    private SysUserService sysUserService;

    private final static Gson GSON = new Gson();

    // region 增删改查

    /**
     * 创建
     *
     * @param taskListAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Boolean> addTaskList(@RequestBody TaskListAddRequest taskListAddRequest, HttpServletRequest request) {
        if (taskListAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        SysUser loginUser = sysUserService.getLoginUser(request);

        TaskList taskList = new TaskList();
        BeanUtils.copyProperties(taskListAddRequest, taskList);


        // 校验时间 频率 任务类型
        taskListService.valid(taskList, true);

        boolean result = taskListService.saveTaskList(taskListAddRequest, loginUser);

        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 更新缓存
//        taskListService.doUpdateCache();

        return ResultUtils.success(true);
    }


    /**
     * 删除
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteTaskList(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        SysUser user = sysUserService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        TaskList oldtaskList = taskListService.getById(id);
        ThrowUtils.throwIf(oldtaskList == null, ErrorCode.NULL_ERROR);

        // 仅本人或管理员可删除
        if (!oldtaskList.getUserId().equals(user.getId()) && !sysUserService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean b = taskListService.removeById(id);
        return ResultUtils.success(b);
    }

    /**
     * 更新（仅管理员）
     *
     * @param taskListUpdateRequest
     * @return
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateTaskList(@RequestBody TaskListUpdateRequest taskListUpdateRequest, HttpServletRequest request) {
        if (taskListUpdateRequest == null || taskListUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        SysUser loginUser = sysUserService.getLoginUser(request);
        List<String> tags = taskListUpdateRequest.getTags();

        TaskList taskList = new TaskList();
        BeanUtils.copyProperties(taskListUpdateRequest, taskList);
        if (!CollectionUtils.isEmpty(tags)) {
            taskList.setTags(GSON.toJson(tags));
        }

        // 参数校验
        taskListService.valid(taskList, false);
        long id = taskListUpdateRequest.getId();
        // 判断是否存在
        TaskList oldtaskList = taskListService.getById(id);
        ThrowUtils.throwIf(oldtaskList == null, ErrorCode.NULL_ERROR);
        // 仅管理员或自己可以修改
        if (!sysUserService.isAdmin(loginUser)) {
            ThrowUtils.throwIf(Objects.equals(loginUser.getId(), oldtaskList.getUserId()), ErrorCode.NO_AUTH_ERROR);
        }

        boolean result = taskListService.updateById(taskList);
        // 更新缓存
        taskListService.doUpdateCache(taskList.getStatus());

        return ResultUtils.success(result);
    }

    @PostMapping("/updateTaskListStatus")
    public BaseResponse<Boolean> updateTaskListStatus(@RequestBody TaskListUpdateRequest taskListUpdateRequest, HttpServletRequest request) {
        if (taskListUpdateRequest == null || taskListUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        SysUser loginUser = sysUserService.getLoginUser(request);
        TaskList taskList = new TaskList();
        BeanUtils.copyProperties(taskListUpdateRequest, taskList);

        long id = taskListUpdateRequest.getId();
        // 判断是否存在
        TaskList oldtaskList = taskListService.getById(id);
        ThrowUtils.throwIf(oldtaskList == null, ErrorCode.NULL_ERROR);
        // 仅管理员或自己可以修改
        if (!sysUserService.isAdmin(loginUser)) {
            ThrowUtils.throwIf(Objects.equals(loginUser.getId(), oldtaskList.getUserId()), ErrorCode.NO_AUTH_ERROR);
        }

        boolean result = taskListService.updateById(taskList);
        // 更新缓存
        taskListService.doUpdateCache(taskList.getStatus());

        return ResultUtils.success(result);
    }


    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    public BaseResponse<TaskList> getTaskListById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TaskList taskList = taskListService.getById(id);
        if (taskList == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        SysUser loginUser = sysUserService.getLoginUser(request);
        // 不是本人或管理员，不能直接获取所有信息
        if (!taskList.getUserId().equals(loginUser.getId()) && !sysUserService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        return ResultUtils.success(taskList);
    }

    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<TaskListVO> getTaskListVOById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TaskList taskList = taskListService.getById(id);
        if (taskList == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        TaskListVO taskListVO = TaskListVO.objToVo(taskList);
        return ResultUtils.success(taskListVO);
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param taskListQueryRequest 查询参数
     * @param request              查询请求
     * @return 分页封装类
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<TaskListVO>> listTaskListVOByPage(@RequestBody TaskListQueryRequest taskListQueryRequest,
                                                               HttpServletRequest request) {
        long current = taskListQueryRequest.getCurrent();
        long size = taskListQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<TaskList> taskListPage = taskListService.page(new Page<>(current, size),
                taskListService.getQueryWrapper(taskListQueryRequest));

        Page<TaskListVO> taskListVOPage = taskListService.getTaskListVOPage(taskListPage, request);

        return ResultUtils.success(taskListVOPage);
    }

    /**
     * 分页获取列表（仅管理员）
     *
     * @param taskListQueryRequest 查询参数
     * @param request              查询请求
     * @return 分页
     */
    @PostMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<TaskList>> listTaskListByPage(@RequestBody TaskListQueryRequest taskListQueryRequest,
                                                           HttpServletRequest request) {
        long current = taskListQueryRequest.getCurrent();
        long size = taskListQueryRequest.getPageSize();
        Page<TaskList> taskListPage = taskListService.page(new Page<>(current, size),
                taskListService.getQueryWrapper(taskListQueryRequest));
        return ResultUtils.success(taskListPage);
    }

    // endregion

    /**
     * 查询我的任务列表
     *
     * @param taskListQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/my")
    public BaseResponse<Page<TaskList>> listMyTaskListByPage(@RequestBody TaskListQueryRequest taskListQueryRequest,
                                                             HttpServletRequest request) {

        SysUser loginUser = sysUserService.getLoginUser(request);

        long current = taskListQueryRequest.getCurrent();
        long size = taskListQueryRequest.getPageSize();
        
        // 不存在startDate endDate 默认查询当日处于进行中的任务 

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startDate = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime endDate = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(0);

        // 否则根据给定时间范围查询
        // (startDate >= now and endDate <= now)  or (status = 1(进行中) and startDate <= now and endDate >= now)
        QueryWrapper<TaskList> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(TaskList::getUserId, loginUser.getId())
                .and(i -> i.ge(TaskList::getStartDate, startDate)
                        .le(TaskList::getEndDate, endDate))
                .or(i -> i.eq(TaskList::getStatus, TaskListStatusEnum.RUNNING.getValue())
                        .le(TaskList::getStartDate, now)
                        .ge(TaskList::getEndDate, now));

        Page<TaskList> taskListPage = taskListService.page(new Page<>(current, size), wrapper);
        return ResultUtils.success(taskListPage);
    }

    /**
     * 查询我的历史人物列表
     *
     * @param taskListQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/my/history")
    public BaseResponse<Page<TaskList>> listMyHistoryTaskListByPage(@RequestBody TaskListQueryRequest taskListQueryRequest,
                                                                    HttpServletRequest request) {

        SysUser loginUser = sysUserService.getLoginUser(request);

        long current = taskListQueryRequest.getCurrent();
        long size = taskListQueryRequest.getPageSize();
        
        AtomicReference<LocalDateTime> startDateRef = new AtomicReference<>(taskListQueryRequest.getStartDate());
        AtomicReference<LocalDateTime> endDateRef = new AtomicReference<>(taskListQueryRequest.getEndDate());

        // 如果开始日期为空，则设置为一个月前的开始时间
        if (startDateRef.get() == null) {
            startDateRef.set(LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).minusMonths(1));
        }

        // 如果结束日期为空，则设置为昨天的结束时间
        if (endDateRef.get() == null) {
            endDateRef.set(LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(0).minusDays(1));
        }
        // 否则根据给定时间范围查询
        QueryWrapper<TaskList> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(TaskList::getUserId, loginUser.getId())
                .and(i -> i.ge(TaskList::getStartDate, startDateRef.get())
                        .le(TaskList::getEndDate, endDateRef.get()))
                .or(i -> i.eq(TaskList::getStatus, TaskListStatusEnum.FINISH.getValue()));

        Page<TaskList> taskListPage = taskListService.page(new Page<>(current, size),
                wrapper);
        return ResultUtils.success(taskListPage);
    }

}
